﻿using System;
using System.Web.Security;
using Wechat.Events;

namespace Wechat
{
    public static class Utilities
    {
        private const double EARTH_RADIUS = 6378137.0;//地球半径(米)

        public static DateTime UnixTimeToTime(string timestamp)
        {
            DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
            long lTime = long.Parse(timestamp + "0000000");
            TimeSpan toNow = new TimeSpan(lTime);
            return dtStart.Add(toNow);
        }

        public static int ConvertDateTimeInt(DateTime time)
        {
            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
            return (int)(time - startTime).TotalSeconds;
        }

        /// <summary>
        /// 验证签名合法
        /// </summary>
        /// <param name="token">源token</param>
        /// <param name="wechatToken"></param>
        /// <returns></returns>
        public static bool ValidSignature(string token, WechatToken wechatToken)
        {
            //if (string.IsNullOrEmpty(wechatToken.Signature) || string.IsNullOrEmpty(wechatToken.Echostr) || string.IsNullOrEmpty(wechatToken.Nonce) || string.IsNullOrEmpty(wechatToken.Timestamp)) { return false; }

            var arrayTemp = new[] { token, wechatToken.Timestamp, wechatToken.Nonce };

            Array.Sort(arrayTemp);

            var value = string.Join(string.Empty, arrayTemp);

            value = FormsAuthentication.HashPasswordForStoringInConfigFile(value, "SHA1").ToLower();

            return value == wechatToken.Signature;
        }

        /// <summary>
        /// 角度数转换为弧度公式
        /// </summary>
        /// <param name="d"></param>
        /// <returns></returns>
        private static double radians(double d)
        {
            return d * Math.PI / 180.0;
        }

        /// <summary>
        /// 弧度转换为角度数公式
        /// </summary>
        /// <param name="d"></param>
        /// <returns></returns>
        private static double degrees(double d)
        {
            return d * (180 / Math.PI);
        }

        /// <summary>
        /// 计算两个经纬度之间的直接距离(google 算法)
        /// </summary>
        public static double GetDistance(Degree degree1, Degree degree2)
        {
            double radLat1 = radians(degree1.Latitude);
            double radLng1 = radians(degree1.Longitude);
            double radLat2 = radians(degree2.Latitude);
            double radLng2 = radians(degree2.Longitude);

            double s = Math.Acos(Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Cos(radLng1 - radLng2) + Math.Sin(radLat1) * Math.Sin(radLat2));
            s = s * EARTH_RADIUS;
            s = Math.Round(s * 10000) / 10000;
            return s;
        }

        /// <summary>
        /// 以一个经纬度为中心计算出四个顶点
        /// </summary>
        /// <param name="distance">半径(米)</param>
        /// <returns></returns>
        public static void GetDegreeCoordinates(Degree degree1, double distance, out Degree leftTop, out Degree leftBottom, out Degree rightTop,out Degree rightBottom)
        {
            double dlng = 2 * Math.Asin(Math.Sin(distance / (2 * EARTH_RADIUS)) / Math.Cos(degree1.Latitude));
            dlng = degrees(dlng);

            double dlat = distance / EARTH_RADIUS;
            dlat = degrees(dlat);

            leftTop = new Degree(Math.Round(degree1.Latitude + dlat, 6), Math.Round(degree1.Longitude - dlng, 6));

            leftBottom = new Degree(Math.Round(degree1.Latitude - dlat, 6), Math.Round(degree1.Longitude - dlng, 6));

            rightTop = new Degree(Math.Round(degree1.Latitude + dlat, 6), Math.Round(degree1.Longitude + dlng, 6));

            rightBottom = new Degree(Math.Round(degree1.Latitude - dlat, 6), Math.Round(degree1.Longitude + dlng, 6));
        }

        public static void GetDegreeRange(Degree leftTop, Degree rightBottom, out double minLat, out double maxLat, out double minLng, out double maxLng)
        {
            minLat = Math.Min(leftTop.Latitude, rightBottom.Latitude);

            maxLat = Math.Max(leftTop.Latitude, rightBottom.Latitude);

            minLng = Math.Min(leftTop.Longitude, rightBottom.Longitude);

            maxLng = Math.Max(leftTop.Longitude, rightBottom.Longitude);
        }
    }
}
